﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Inovout.Data.Repository;
using Inovout.Web.Mvc;

namespace System.Web.Mvc.Html
{
    /// <summary>
    /// Widget-Query
    /// </summary>
    public static class QueryExtensions
    {
        /// <summary>
        /// 生成查询条件Html
        /// </summary>
        /// <typeparam name="TModel">集合中模型类型</typeparam>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <returns>QueryCriteriaModelHelper对象实例</returns>
        public static QueryCriteriaModelHelper<TModel> Query<TModel>(this HtmlHelper<IEnumerable<TModel>> html)
        {
            QueryCriteriaModel qeryCriteriaModel = new QueryCriteriaModel(typeof(TModel), html.ViewData);
            return new QueryCriteriaModelHelper<TModel>(html, qeryCriteriaModel);
        }
        /// <summary>
        /// 查询条件模型辅助类
        /// </summary>
        /// <typeparam name="TModel">集合中的模型</typeparam>
        public class QueryCriteriaModelHelper<TModel> : IHtmlString
        {
            internal QueryCriteriaModelHelper(HtmlHelper html, QueryCriteriaModel qeryCriteriaModel)
            {
                this.html = html;
                this.QeryCriteriaModel = qeryCriteriaModel;
                this.queryCriteriaBuilder = new QueryCriteriaBuilder<TModel>(QeryCriteriaModel);
            }

            private readonly QueryCriteriaBuilder<TModel> queryCriteriaBuilder;
            private HtmlHelper html;

            /// <summary>
            /// 查询条件模型
            /// </summary>
            public QueryCriteriaModel QeryCriteriaModel { get; private set; }
            /// <summary>
            /// 增加过滤条件
            /// </summary>
            /// <typeparam name="TProperty">属性类型</typeparam>
            /// <param name="expression">属性访问器表达式</param>
            /// <returns>QueryCriteriaModelHelper对象实例</returns>
            public QueryCriteriaModelHelper<TModel> FilterFor<TProperty>(Expression<Func<TModel, TProperty>> expression)
            {
                return FilterFor(expression, FilterBinary.Eq);
            }
            /// <summary>
            /// 增加过滤条件
            /// </summary>
            /// <typeparam name="TProperty">属性类型</typeparam>
            /// <param name="expression">属性访问器表达式</param>
            /// <param name="operation">过滤操作</param>
            /// <returns>QueryCriteriaModelHelper对象实例</returns>
            public QueryCriteriaModelHelper<TModel> FilterFor<TProperty>(Expression<Func<TModel, TProperty>> expression, FilterBinary operation)
            {
                if (operation == FilterBinary.Range)
                {
                    queryCriteriaBuilder.FilterFor(expression, FilterOperation.GtEq);
                    queryCriteriaBuilder.FilterFor(expression, FilterOperation.LeEq);
                }
                else
                {
                    queryCriteriaBuilder.FilterFor(expression, (FilterOperation)(int)operation);
                }
                return this;
            }
            /// <summary>
            /// 增加排序规则
            /// </summary>
            /// <typeparam name="TProperty">属性类型</typeparam>
            /// <param name="orderPropertyNameExpression">排序属性名表达式</param>
            /// <param name="ascending">是否正序</param>
            /// <returns>QueryCriteriaModelHelper对象实例</returns>
            public QueryCriteriaModelHelper<TModel> OrderFor<TProperty>(Expression<Func<TModel, TProperty>> orderPropertyNameExpression, bool ascending = true)
            {
                this.queryCriteriaBuilder.OrderFor(orderPropertyNameExpression, ascending);
                return this;
            }
            /// <summary>
            /// 增加倒序规则
            /// </summary>
            /// <typeparam name="TProperty">属性类型</typeparam>
            /// <param name="orderPropertyNameExpression">排序属性名表达式</param>
            /// <returns>QueryCriteriaModelHelper对象实例</returns>
            public QueryCriteriaModelHelper<TModel> OrderDescendingFor<TProperty>(Expression<Func<TModel, TProperty>> orderPropertyNameExpression)
            {
                this.queryCriteriaBuilder.OrderDescendingFor(orderPropertyNameExpression);
                return this;
            }
            public string ToHtmlString()
            {
                QeryCriteriaModel.Merge(html.ViewData.GetFilterCriterias((IEnumerable)html.ViewData.Model),
                            html.ViewData.GetOrderCriterias((IEnumerable)html.ViewData.Model));
                html.ViewData.SetFilterCriterias(QeryCriteriaModel.Filters, (IEnumerable)html.ViewData.Model);
                html.ViewData.SetOrderCriterias(QeryCriteriaModel.Orders.ToArray(), (IEnumerable)html.ViewData.Model);
                return html.ModelEditor<QueryCriteriaModel>(QeryCriteriaModel, "_Query").ToString();

            }
        }

        public static void Filter<TModel>(this HtmlHelper html)
        {
            var filters = html.ViewData.GetFilterCriterias((IEnumerable)html.ViewData.Model);
            var model = new FilterCriteriaCollectionModel(typeof(TModel), html.ViewData);
            model.Merge(filters);
            html.ViewContext.Writer.Write(html.ModelEditor<FilterCriteriaCollectionModel>(model, "_Filter"));
        }
        public static void Order(this HtmlHelper html)
        {
            var orders = html.ViewData.GetOrderCriterias((IEnumerable)html.ViewData.Model);

            html.ViewContext.Writer.Write(html.ModelEditor<OrderCriteria[]>(orders.ToArray(), "_Order"));
        }
        public static void FilterAndOrder<TModel>(this HtmlHelper html)
        {
            Filter<TModel>(html);
            Order(html);
        }
    }
}
